In [1]:
import sys; sys.path.append('../..')
from puzzles import leet_puzzle
leet_puzzle('rotate-array')
In [4]:
n, k = 7, 4
example_array = list(range(n))
example_array
Out[4]:
In [5]:
def rotate_simple(input_array, order):
order %= len(input_array)
return input_array[order:] + input_array[:order]
rotate_simple(example_array, k)
Out[5]:
In [9]:
%%timeit
rotate_simple(example_array, k)
This solution has both time and space complexity of O(n).
However if we want to rotate a large array in place (without creating a new array), the solution above is inefficient. The time complexity is O(n), dependant only on the size of the input array, but the space complexity is also O(n) since we need to create a new array with the rotated elements. By applying a similar algorithm to bubble sort we can perform the rotation in place.
In [10]:
def rotate_bubble_inplace(input_array, order):
order %= len(input_array)
for i in range(order):
for j in range(len(input_array)):
input_array[j], input_array[j - 1] = input_array[j - 1], input_array[j]
return input_array
example_array2 = list(example_array)
rotate_bubble_inplace(example_array2, k)
Out[10]:
In [11]:
%%timeit
rotate_bubble_inplace(example_array, k)
However, although the space complexity is now O(1), the time complexity is O(n * k). It would be good to find a solution that has O(1) space complexity and O(n) time complexity.
In [12]:
def rotate_reverse_inplace(input_array, order):
length = len(input_array)
order = -order % length
split_location = length - order
input_array[:split_location] = reversed(input_array[:split_location])
input_array[split_location:] = reversed(input_array[split_location:])
input_array.reverse()
return input_array
example_array2 = list(example_array)
rotate_reverse_inplace(example_array2, k)
Out[12]:
In [13]:
%%timeit
rotate_reverse_inplace(example_array, k)